﻿using Common;
using DataLibrary;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace ImageUploader
{
    public class Monitor
    {
        #region 静态变量
        private static Thread threadMonitor = null;
        private static string imagePath;
        private static int operationFlag = 0;
        private static ListBox listB;
        private static FileSystemWatcher watcher;
        private static Hashtable htCode;
        private static ImageManagerEntities ime = new ImageManagerEntities();
        private static byte[] _buffer = new byte[102400];
        private static int _receiveCount = 0;
        private static string _receiveString = string.Empty;
        private static Socket transferSocket = null;
        private static int flag = 0;//标记是否是断点续传，0则表示正常传输，小于0则表示传输中断
        private static BreakPointPost _bpp = null;
        private static BreakPointPost _breakBpp = null;

        private static List<string> fileList = new List<string>();
        #endregion
        public static void monitorFile(string path, ListBox listBox, Hashtable ht)
        {
            listB = listBox;
            imagePath = path;
            htCode = ht;
            try
            {
                threadMonitor = null;
                string qualifiedPath = string.Format("{0}/合格", imagePath);
                string unQualifiedPath = string.Format("{0}/不合格", imagePath);
                htCode.Add("qualityID", 0);//初始化质量id，根据路径给值；
                if (!Directory.Exists(qualifiedPath))
                    Directory.CreateDirectory(qualifiedPath);
                if (!Directory.Exists(unQualifiedPath))
                    Directory.CreateDirectory(unQualifiedPath);
                threadMonitor = new Thread(monitor);
                threadMonitor.IsBackground = true;
                threadMonitor.Start();
                ShowMsg.showMsg(listB, "开始监控指定图片目录:" + imagePath);
            }
            catch (Exception ex)
            {
                ShowMsg.showMsg(listB, ex.Message);
            }
        }

        public static void monitor()
        {
            try
            {
                if (watcher != null)
                {                    
                    watcher.Dispose();
                }
                watcher = new FileSystemWatcher(imagePath);
                watcher.EnableRaisingEvents = true;
                watcher.Created += new FileSystemEventHandler(OnCreated);
                watcher.Deleted += new FileSystemEventHandler(OnDeleted);
                watcher.Renamed += new RenamedEventHandler(OnRenamed);
                watcher.IncludeSubdirectories = true;
            }
            catch(Exception ex)
            {
                ShowMsg.showMsg(listB, ex.Message);
            }
        }

        private static void OnCreated(object sender, FileSystemEventArgs e)
        {
            string debug = string.Format("检测到新文件，{0}:{1}", e.ChangeType, e.Name);
            if (e.Name.Contains("不合格"))
                htCode["qualityID"] = 2;//这里先固定合格就是1，不合格就是2，不从库里查了；
            else
                htCode["qualityID"] = 1;
            //string filetype = PublicMethod.IsAllowedExtension(e.FullPath);
            string filetype = Path.GetExtension(e.FullPath);
            operationFlag = 1;

            if (filetype == "255216" || filetype == "6677" || filetype == "13780" || filetype == ".bmp" || filetype == ".jpg")
            {
                if (e.Name.Contains("-"))
                {
                    ShowMsg.showMsg(listB, "文件名称不能含有‘-’" + e.Name, 2);
                }
                else
                {
                    try
                    {
                        #region 先不删，这个方法是用tcpclient和redis配合使用，比较复杂，不如直接用socket灵活，先留着
                        //cnt++;
                        //ShowMsg.showMsg(listB, debug);
                        //string oriFileName = Path.GetFileNameWithoutExtension(e.FullPath);
                        //string newFileName = oriFileName + "-" + htCode["FileNameExt"];
                        //htCode["newFileName"] = newFileName;
                        //Send_File(e.FullPath);
                        //insertSql += string.Format("('{0}','{1}',{2},{3},{4},'{5}'),", newFileName, (string)htCode["fileSize"], (int)htCode["machineID"], (int)htCode["qualityID"], (int)htCode["teamID"], e.FullPath);
                        //RedisHelper.Set<Hashtable>("args", htCode, DateTime.Now.AddHours(1) - DateTime.Now);
                        //if (cnt >= 2)
                        //{                        
                        //    string finalsql = string.Format("insert into ImageInfo(ImagePath, ImageSize, MachineID, QualityID, TeamID, OriginPath) values {0}", insertSql.Substring(0, insertSql.Length - 1));                        
                        //    ime.Database.ExecuteSqlCommand(finalsql);
                        //    insertSql = "";
                        //    cnt = 0;
                        //}
                        #endregion
                        fileList.Add(e.FullPath);
                        _bpp = new BreakPointPost();
                        _bpp.FileName = htCode["qualityID"] + Path.GetFileNameWithoutExtension(e.FullPath) + "-" + htCode["code"] + "-" + DateTime.Now.ToString("yyyyMMddHHmmssffff") + ".bmp";//what a crazy filename!;
                        _bpp.FileSize = new FileInfo(e.FullPath).Length;
                        _bpp.FilePath = e.FullPath;
                        _bpp.PackageSize = 102400;
                        _bpp.PackageCount = GetFilePackageCount(_bpp.FileSize, _bpp.PackageSize);
                        _bpp.Index = 0;
                        if (flag < 0 && _breakBpp!=null)
                        {
                            if(_bpp.FilePath == _breakBpp.FilePath && _bpp.PackageCount == _breakBpp.PackageCount)
                                //确认是不是上传没有传输完成的文件
                               _bpp = _breakBpp;
                        }                        
                        SendToServer();
                    }
                    catch (Exception ex)
                    {
                        ShowMsg.showMsg(listB, ex.Message, 2);
                    }
                }
            }
            else
            {
                ShowMsg.showMsg(listB, "检测到文件不是图片文件" + e.Name, 2);
            }
        }
        #region 一些违规操作的记录
        private static void OnDeleted(object sender, FileSystemEventArgs e)
        {
            string debug = string.Format("{0}:{1}", e.ChangeType, e.Name);
            if (operationFlag < 1)
            {
                MessageBox.Show("该操作属于违规操作，您的操作已被记录！", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                debug = string.Format("{0}-{1}:{2}", "操作员:" + GetUserInfo.UserNum + "进行了违规删除操作，具体动作为", e.ChangeType, e.Name);
            }
            //logger.Warn(debug);
            ShowMsg.showMsg(listB, debug, 2);
        }
        private static void OnRenamed(object sender, RenamedEventArgs e)
        {
            string debug = string.Format("{0}:{1}", e.ChangeType, e.Name);
            if (operationFlag < 1)
            {
                MessageBox.Show("该操作属于违规操作，您的操作已被记录！", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                debug = string.Format("{0}-{1}:{2}", "操作员:" + GetUserInfo.UserNum + "进行了违规重命名操作，具体动作为", e.ChangeType, e.Name);
            }
            //logger.Warn(debug);
            ShowMsg.showMsg(listB, debug, 2);
        }
        private static void Changed(object sender, FileSystemEventArgs e)
        {
            string debug = string.Format("{0}:{1}", e.ChangeType, e.Name);
            if (operationFlag < 1)
            {
                MessageBox.Show("该操作属于违规操作，您的操作已被记录！", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                debug = string.Format("{0}-{1}:{2}", "操作员:" + GetUserInfo.UserNum + "进行了违规修改文件操作，具体动作为", e.ChangeType, e.Name);
            }
            //logger.Warn(debug);
            ShowMsg.showMsg(listB, debug, 2);
        }
        #endregion

        /// <summary>
        /// 关闭连接
        /// </summary>
        public static void CloseTcpSocket()
        {
            if (MessageBox.Show("关闭连接会导致图片无法及时上传到图片服务器，确定要关闭链接吗？", "警告", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
            {
                if(_bpp!= null &&_bpp.Index != _bpp.PackageCount)
                    flag = -1;
                if (transferSocket != null)
                {
                    transferSocket.Close();//关闭client
                    transferSocket.Dispose();
                }
                if (threadMonitor != null)
                    threadMonitor.Abort();//关闭监控线程                
                string msg = string.Format("员工编号为{0},关闭了上传通道", GetUserInfo.UserNum);
                ShowMsg.showMsg(listB, msg);
            }
        }

        private static void SendToServer()
        {
            IPAddress ip = IPAddress.Parse(ConfigurationSettings.AppSettings["Server"].ToString());
            IPEndPoint ep = new IPEndPoint(ip, 50001);
            
            using (transferSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                try
                {
                    transferSocket.Connect(ep);
                    ShowMsg.showMsg(listB, "connect success...");
                    while (true)
                    {
                        _receiveCount = transferSocket.Receive(_buffer);
                        _receiveString = Encoding.UTF8.GetString(_buffer, 0, _receiveCount);
                        if (_receiveString == "yes")
                            break;
                        Thread.Sleep(100);
                    }
                    var bpp = _bpp;                                            
                    transferSocket.Send(Encoding.UTF8.GetBytes("ready to transfor"));
                    Thread.Sleep(1200);
                    transferSocket.Send(Encoding.UTF8.GetBytes("send argument"));
                    ShowMsg.showMsg(listB, "send argument");
                    transferSocket.Send(Encoding.UTF8.GetBytes("FileName|" + bpp.FileName));
                    ShowMsg.showMsg(listB, "FileName|" + bpp.FileName);
                    Thread.Sleep(500);
                    transferSocket.Send(Encoding.UTF8.GetBytes("FilePath|" + bpp.FilePath));
                    ShowMsg.showMsg(listB, "FilePath|" + bpp.FilePath);
                    Thread.Sleep(500);
                    transferSocket.Send(Encoding.UTF8.GetBytes("FileSize|" + bpp.FileSize));
                    ShowMsg.showMsg(listB, "FileSize|" + bpp.FileSize);
                    Thread.Sleep(500);
                    transferSocket.Send(Encoding.UTF8.GetBytes("PackageSize|" + bpp.PackageSize));
                    ShowMsg.showMsg(listB, "PackageSize|" + bpp.PackageSize);
                    Thread.Sleep(500);
                    transferSocket.Send(Encoding.UTF8.GetBytes("PackageCount|" + bpp.PackageCount));
                    ShowMsg.showMsg(listB, "PackageCount|" + bpp.PackageCount);
                    Thread.Sleep(500);
                    transferSocket.Send(Encoding.UTF8.GetBytes("Index|" + bpp.Index));
                    ShowMsg.showMsg(listB, "Index|" + bpp.Index);
                    Thread.Sleep(500);
                    while (true)
                    {
                        _receiveCount = transferSocket.Receive(_buffer);
                        _receiveString = Encoding.UTF8.GetString(_buffer, 0, _receiveCount);
                        if (_receiveString == "argument received")
                            break;
                    }
                    Thread.Sleep(100);
                    transferSocket.Send(Encoding.UTF8.GetBytes("start"));
                    ShowMsg.showMsg(listB, bpp.FileName + "，start transfor");
                    Thread.Sleep(100);
                    while (true)
                    {
                        if (flag < 0)
                        {
                            flag = 0;
                            transferSocket.Send(Encoding.UTF8.GetBytes("stop"));
                            Thread.Sleep(1200);
                            transferSocket.Send(Encoding.UTF8.GetBytes("client failure, please wait a moment, restarting..."));
                            Thread.Sleep(1200);
                            transferSocket.Send(Encoding.UTF8.GetBytes("restart"));
                            Thread.Sleep(1200);
                        }
                        transferSocket.Send(Encoding.UTF8.GetBytes("Index|" + bpp.Index));
                        Thread.Sleep(100);
                        _buffer = FileRead(bpp.FilePath, bpp.Index, bpp.PackageSize);
                        transferSocket.Send(_buffer, 0, _buffer.Length, SocketFlags.None);
                        var bufferLength = _buffer.Length;
                        Thread.Sleep(100);

                        _receiveCount = transferSocket.Receive(_buffer);
                        _receiveString = Encoding.UTF8.GetString(_buffer, 0, _receiveCount);
                        if (_receiveString.Contains("success") && _receiveString.Split('|')[1] == bpp.Index.ToString())
                        {
                            bpp.Index++;
                            //_index = bpp.Index;
                            _breakBpp = bpp;//实时将传输状态记录下来
                            ShowMsg.showMsg(listB, string.Format("index is {0}/{1}({2})", bpp.Index, bpp.PackageCount, bufferLength));
                            if (bpp.Index == bpp.PackageCount) break;
                        }

                        else
                        {
                            Thread.Sleep(100);
                            continue;
                        }
                    }
                    transferSocket.Send(Encoding.UTF8.GetBytes("finish"));
                    ShowMsg.showMsg(listB, bpp.FileName + "，finish");
                }
                catch (Exception ex)
                {
                    ShowMsg.showMsg(listB, ex.Message);
                    flag = -1;
                }
                finally
                {
                    ShowMsg.showMsg(listB, "server:" + transferSocket.RemoteEndPoint.ToString() + "disconnect...");
                    transferSocket.Close();
                    Thread.Sleep(1000);
                }
            }
        }

        private static int GetFilePackageCount(long fileSize, long packageSize)
        {
            int count = 0;
            if (fileSize % packageSize > 0)
                count = Convert.ToInt32(fileSize / packageSize) + 1;
            else
                count = Convert.ToInt32(fileSize / packageSize);
            return count;
        }
        private static byte[] FileRead(string path, int index, long size)
        {
            byte[] result = null;
            long length = (long)index * (long)size + size;
            using (FileStream stream = File.OpenRead(path))
            {
                if (length > stream.Length)
                    result = new byte[stream.Length - ((long)index * (long)size)];
                else
                    result = new byte[size];
                stream.Seek((long)index * (long)size, SeekOrigin.Begin);
                stream.Read(result, 0, result.Length);
                stream.Close();
            }
            return result;
        }
        public class BreakPointPost
        {
            public string FileName { get; set; }
            public string FilePath { get; set; }
            public long FileSize { get; set; }
            public long PackageSize { get; set; }
            public int PackageCount { get; set; }            
            public int Index { get; set; }
        }

       
    }
}
